package edu.boun.g4.coursity.controller;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import javax.annotation.Resource;

import org.jsoup.Jsoup;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import edu.boun.g4.coursity.domain.Course;
import edu.boun.g4.coursity.domain.CoursityUser;
import edu.boun.g4.coursity.domain.Rating;
import edu.boun.g4.coursity.dto.CourseDto;
import edu.boun.g4.coursity.dto.RatingDto;
import edu.boun.g4.coursity.service.CommentService;
import edu.boun.g4.coursity.service.CourseService;
import edu.boun.g4.coursity.service.InitiativeService;
import edu.boun.g4.coursity.service.InstitutionService;
import edu.boun.g4.coursity.service.InstructorService;
import edu.boun.g4.coursity.service.LanguageService;
import edu.boun.g4.coursity.service.RatingService;
import edu.boun.g4.coursity.service.SemanticTagService;
import edu.boun.g4.coursity.service.UserService;

import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.model.GenericDataModel;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.CachingRecommender;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.AveragingPreferenceInferrer;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;

/**
 * @author mertusta
 * @author bulutkorkmaz
 * 
 *         Handles and retrieves course request
 */
@Controller
@RequestMapping("/course")
public class CourseController {

	@Resource(name = "courseService")
	private CourseService courseService;

	@Resource(name = "initiativeService")
	private InitiativeService initiativeService;

	@Resource(name = "institutionService")
	private InstitutionService institutionService;

	@Resource(name = "instructorService")
	private InstructorService instructorService;

	@Resource(name = "languageService")
	private LanguageService languageService;

	@Resource(name = "commentService")
	private CommentService commentService;

	@Resource(name = "semanticTagService")
	private SemanticTagService semanticTagService;
	
	@Resource(name = "userService")
	private UserService userService;

	@Resource(name = "ratingService")
	private RatingService ratingService;
	@RequestMapping(method = RequestMethod.POST, value = "/add")
	public @ResponseBody
	Response addCourse(@RequestParam String description,
			@RequestParam String name, @RequestParam Integer rating,
			@RequestParam String info, @RequestParam String url,
			@RequestParam String length, @RequestParam String estimatedEffort,
			@RequestParam String certificate, @RequestParam String textbook,
			@RequestParam String country, @RequestParam Boolean peerAssesment,
			@RequestParam Boolean teamProjects, @RequestParam Boolean exam,
			@RequestParam Boolean videoLectures, @RequestParam Boolean forum) {

		Course course = new Course();
		course.setCourseDescription(description);
		course.setCourseName(name);
		course.setRating(rating);
		// course.setInitiative(null);
		// course.setInstitution(null);
		// course.setInstructors(null);
		// course.setCategories(null);
		// course.setLanguages(null);
		// course.setComments(null);
		// course.setStartingDate(null);
		course.setInfo(info);
		course.setUrl(url);
		course.setLength(length);
		course.setEstimatedEffort(estimatedEffort);
		// course.setPrerequisites(null);
		// course.setRecommendedBackground(null);
		course.setCertificate(certificate);
		course.setTextbook(textbook);
		course.setCountry(country);
		course.setPeerAssesment(peerAssesment);
		course.setTeamProjects(teamProjects);
		course.setExam(exam);
		course.setVideoLectures(videoLectures);
		course.setForum(forum);

		Response response = new Response();
		response.setBody(course);
		response.setStatus(true);

		courseService.add(course);

		return response;
	}

	@RequestMapping(method = RequestMethod.POST, value = "/delete")
	public @ResponseBody
	Response deleteRating(@RequestParam Integer id) {

		Response response = new Response();
		response.setBody(null);
		response.setStatus(true);

		courseService.delete(id);

		return response;
	}

	@RequestMapping(method = RequestMethod.POST, value = "/edit")
	public @ResponseBody
	Response editCourse(@RequestParam String description,
			@RequestParam String name, @RequestParam Integer rating,
			@RequestParam String info, @RequestParam String url,
			@RequestParam String length, @RequestParam String estimatedEffort,
			@RequestParam String certificate, @RequestParam String textbook,
			@RequestParam String country, @RequestParam Boolean peerAssesment,
			@RequestParam Boolean teamProjects, @RequestParam Boolean exam,
			@RequestParam Boolean videoLectures, @RequestParam Boolean forum) {

		Course existingCourse = new Course();
		existingCourse.setCourseDescription(description);
		existingCourse.setCourseName(name);
		existingCourse.setRating(rating);
		// existingCourse.setInitiative(null);
		// existingCourse.setInstitution(null);
		// existingCourse.setInstructors(null);
		// existingCourse.setCategories(null);
		// existingCourse.setLanguages(null);
		// existingCourse.setComments(null);
		// existingCourse.setStartingDate(null);
		existingCourse.setInfo(info);
		existingCourse.setUrl(url);
		existingCourse.setLength(length);
		existingCourse.setEstimatedEffort(estimatedEffort);
		// existingCourse.setPrerequisites(null);
		// existingCourse.setRecommendedBackground(null);
		existingCourse.setCertificate(certificate);
		existingCourse.setTextbook(textbook);
		existingCourse.setCountry(country);
		existingCourse.setPeerAssesment(peerAssesment);
		existingCourse.setTeamProjects(teamProjects);
		existingCourse.setExam(exam);
		existingCourse.setVideoLectures(videoLectures);
		existingCourse.setForum(forum);

		Response response = new Response();
		response.setBody(null);
		response.setStatus(true);

		courseService.edit(existingCourse);

		return response;
	}

	@RequestMapping(method = RequestMethod.POST, value = "/getCourse")
	public @ResponseBody
	Response getCourse(@RequestParam Integer id) {

		Course course = courseService.get(id);
		CourseDto dto = new CourseDto();

		dto.setCategories(semanticTagService.getAllCategories(course
				.getCourseId()));
		dto.setCertificate(course.getCertificate());
		dto.setComments(commentService.getAll(course.getCourseId()));
		dto.setCountry(course.getCountry());
		dto.setCourseDescription(course.getCourseDescription());
		dto.setCourseId(course.getCourseId());
		dto.setCourseName(course.getCourseName());
		dto.setEstimatedEffort(course.getEstimatedEffort());
		dto.setExam(course.isExam());
		dto.setForum(course.isForum());
		dto.setInfo(course.getInfo());
		dto.setInitiative(initiativeService.getAll(course.getCourseId()));
		dto.setInstitution(institutionService.getAll(course.getCourseId()));
		dto.setInstructor(instructorService.getAll(course.getCourseId()));
		dto.setLanguages(course.getLanguages());
		dto.setLength(course.getLength());
		dto.setPeerAssesment(course.isPeerAssesment());
		dto.setPrerequisites(courseService.getAllPrerequisite(course
				.getCourseId()));
		dto.setRating(course.getRating());
		dto.setRecommendedBackground(course.getRecommendedBackground());
		dto.setStartingDate(course.getStartingDate());
		dto.setTeamProjects(course.isTeamProjects());
		dto.setTextbook(course.getTextbook());
		dto.setUrl(course.getUrl());
		dto.setVideoLectures(course.isVideoLectures());

		Response response = new Response();
		response.setBody(dto);
		response.setStatus(true);

		return response;
	}

	@RequestMapping(method = RequestMethod.POST, value = "/list")
	public @ResponseBody
	Response listCourses(@RequestParam String listType) {

		List<Course> all = courseService.getAll(listType);
		List<CourseDto> dtos = new ArrayList<CourseDto>();

		CourseDto dto;
		for (Course course : all) {
			dto = new CourseDto();
			dto.setCategories(semanticTagService.getAllCategories(course
					.getCourseId()));
			dto.setCertificate(course.getCertificate());
			dto.setComments(commentService.getAll(course.getCourseId()));
			dto.setCountry(course.getCountry());
			dto.setCourseDescription(Jsoup.parse(course.getCourseDescription()).text().substring(0, 100)+"...");
			dto.setCourseId(course.getCourseId());
			dto.setCourseName(course.getCourseName());
			dto.setEstimatedEffort(course.getEstimatedEffort());
			dto.setExam(course.isExam());
			dto.setForum(course.isForum());
			dto.setInfo(course.getInfo());
			dto.setInitiative(initiativeService.getAll(course.getCourseId()));
			dto.setInstitution(institutionService.getAll(course.getCourseId()));
			dto.setInstructor(instructorService.getAll(course.getCourseId()));
			dto.setLanguages(course.getLanguages());
			dto.setLength(course.getLength());
			dto.setPeerAssesment(course.isPeerAssesment());
			dto.setPrerequisites(courseService.getAllPrerequisite(course
					.getCourseId()));
			dto.setRating(course.getRating());
			dto.setRecommendedBackground(course.getRecommendedBackground());
			dto.setStartingDate(course.getStartingDate());
			dto.setTeamProjects(course.isTeamProjects());
			dto.setTextbook(course.getTextbook());
			dto.setUrl(course.getUrl());
			dto.setVideoLectures(course.isVideoLectures());

			dtos.add(dto);
		}

		Response response = new Response();
		response.setBody(dtos);
		response.setStatus(true);

		return response;
	}

	@RequestMapping(value = "/test")
	public @ResponseBody
	Response test() {

		Course course = new Course();
		course.setCourseDescription("Test Course Description!");
		course.setCourseName("Test Course");
		course.setRating(0);
		course.setInitiative(initiativeService.get(1));
		// course.setInstitution(null);
		// course.setInstructors(null);
		// course.setCategories(null);
		// course.setLanguages(null);
		// course.setComments(null);
		// course.setStartingDate(null);
		course.setInfo("Test Info");
		course.setUrl("http://testcourse");
		course.setLength("1 week");
		course.setEstimatedEffort("15 hours/week");
		// course.setPrerequisites(null);
		// course.setRecommendedBackground(null);
		course.setCertificate("Test Certificate");
		course.setTextbook("Test Book");
		course.setCountry("Test Country");
		course.setPeerAssesment(false);
		course.setTeamProjects(false);
		course.setExam(false);
		course.setVideoLectures(false);
		course.setForum(false);

		Response response = new Response();
		response.setBody(course);
		response.setStatus(true);

		courseService.add(course);

		return response;
	}
	
	@RequestMapping(method = RequestMethod.POST, value = "/listRecommendedCourses")
	public @ResponseBody
	Response listRecommendedCourses(int userid) throws Exception{
	
		List<RecommendedItem> recommendations = null;

		try {
			
			List<RatingDto> allratings = new ArrayList<RatingDto>();		
			List<Rating> all = ratingService.getAll();
			for(Iterator<Rating> i = all.iterator(); i.hasNext(); ) {
				Rating item = i.next();
				Course c = item.getCourse();	
				int cId = 0;
				if (c != null)
				{
					cId = c.getCourseId();
				}
				
				CoursityUser cUser = item.getCousityUser();
				int cUserId = 0;
				if (cUser != null)
				{
					cUserId = cUser.getId();
				}	
				
				allratings.add(new RatingDto(cUserId, cId, item.getRatingScore(),item.getId()));
			}					 
			
			if (allratings != null)
			{				
				//model = ratings;
				// Data should be in the form of "userID,itemID,prefValue" (e.g. "39505,290002,3.5")
				//DataModel model = new FileDataModel(new File("C:\\temp\\data\\data.txt"));
				DataModel model = new CourseDataModel(allratings);		
				
				if (model != null)
				{					
					UserSimilarity userSimilarity = new PearsonCorrelationSimilarity(model);
					
					// Optional:
					userSimilarity.setPreferenceInferrer(new AveragingPreferenceInferrer(model));
					
					UserNeighborhood neighborhood = new NearestNUserNeighborhood(3, userSimilarity, model);
					
					Recommender recommender = new GenericUserBasedRecommender(model, neighborhood, userSimilarity);
					Recommender cachingRecommender = new CachingRecommender(recommender);
					
					recommendations =cachingRecommender.recommend(userid, 10);
				}
			}

		} catch (TasteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
		
		Response response = new Response();
		response.setBody(recommendations);
		response.setStatus(true);

		return response;		
	
	}
	
	@RequestMapping(value = "/listRecommendedCoursesTest")
	public @ResponseBody
	Response listRecommendedCoursesTest() throws Exception{
	
		int userid =1;
	
		return listRecommendedCourses(userid);
	
	}

}